package br.mestrado.unb.bs.protocol;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import br.mestrado.unb.bs.communication.BluetoothConnection;
import br.mestrado.unb.bs.communication.IBluetoothWriter;
import br.mestrado.unb.bs.model.configuration.SensorConfiguration;
import br.mestrado.unb.bs.model.configuration.SensorIdentification;
import br.mestrado.unb.bs.model.constant.DataPackageConstant;
import br.mestrado.unb.bs.model.sensor.AccPayload;
import br.mestrado.unb.bs.model.sensor.CommandPayload;
import br.mestrado.unb.bs.model.sensor.DataPackageWrapper;
import br.mestrado.unb.bs.model.sensor.EcgPayload;
import br.mestrado.unb.bs.model.sensor.Spo2Payload;
import br.mestrado.unb.bs.model.sensor.TemperaturePayload;
import br.mestrado.unb.bs.sensor.AccSensorThread;
import br.mestrado.unb.bs.sensor.EcgSensorThread;
import br.mestrado.unb.bs.sensor.SPO2SensorThread;
import br.mestrado.unb.bs.sensor.TemperatureSensorThread;
import br.mestrado.unb.bs.view.ISensorWindow;

public class ProtocolController extends Thread{
	
	private IBluetoothWriter writer;
	private ProtocolParser buffer = null;
	private boolean isSensing = false;
	private boolean run = true;
	
	private Map<SensorIdentification, ISensorWindow> sensorWindow;
	
	private List<SPO2SensorThread> spo2s = null;
	private List<TemperatureSensorThread> temperatures = null;
	private List<EcgSensorThread> ecgs = null;
	private List<AccSensorThread> accs = null;
	
	private SensorConfiguration sensorConfig = null;


	public ProtocolController(ProtocolParser buffer, SensorConfiguration config, IBluetoothWriter writer) {
		this.writer = writer;
		this.sensorConfig = config;
		this.buffer = buffer;
		this.isSensing = false;
		this.sensorWindow  = new HashMap<SensorIdentification, ISensorWindow>();
		
		this.spo2s = new ArrayList<SPO2SensorThread>();
		this.temperatures= new ArrayList<TemperatureSensorThread>();
		this.ecgs = new ArrayList<EcgSensorThread>();
		this.accs = new ArrayList<AccSensorThread>();
		
		this.setName("ProtocolController");
	}
	
	public void onDestroy() {
		this.run = false;
		stopSPO2s();
		stopTemperatures();
		stopEcgs();
		stopAccs();
		clearSensorWindow();
	}

	private void clearSensorWindow() {
		if(sensorWindow!=null){
			sensorWindow.clear();
		}
	}
	
	private void stopAccs() {
		if(accs!=null){
			for (AccSensorThread obj : accs) {
				if(obj.isAlive()){
					obj.interrupt();
				}
			}
			accs.clear();
			accs = new ArrayList<AccSensorThread>();
		}
	}
	
	private void stopEcgs() {
		if(ecgs!=null){
			for (EcgSensorThread obj : ecgs) {
				if(obj.isAlive()){
					obj.interrupt();
				}
			}
			ecgs.clear();
			ecgs = new ArrayList<EcgSensorThread>();
		}
	}
	
	private void stopTemperatures() {
		if(temperatures!=null){
			for (TemperatureSensorThread obj : temperatures) {
				if(obj.isAlive()){
					obj.interrupt();
				}
			}
			temperatures.clear();
			temperatures = new ArrayList<TemperatureSensorThread>();
		}
	}

	private void stopSPO2s() {
		if(spo2s!=null){
			for (SPO2SensorThread spo2 : spo2s) {
				if(spo2.isAlive()){
					spo2.interrupt();
				}
			}
			spo2s.clear();
			spo2s = new ArrayList<SPO2SensorThread>();
		}
	}

	@Override
	public void run() {
	
		while(run){
			List<DataPackageWrapper> list = null;
			if((list=this.buffer.getDataPackageWrappers())!=null){
				for (int i = 0; i < list.size(); i++) {
					DataPackageWrapper dp = list.get(i);
					if(dp.getPayload() instanceof CommandPayload){
						CommandPayload comm = (CommandPayload) dp.getPayload();
						if(isStartCommand(comm)){
							startSensing();
						}else if(isStopCommand(comm)){
							stopSensing();
						}else if(isSearchCommand(comm)){
							//searchSensors();
						}
					}
				}
			}
		}
		
	}
	

	private void startSensing() {
		if(!this.isSensing){
			this.startSPO2s();
			this.startTemperatures();
			this.startEcgs();
			this.startAccs();
			this.isSensing = true;
		}
	}

	private void startEcgs() {
		if(sensorConfig!=null){
			List<SensorIdentification> sensors = sensorConfig.getSensor(EcgPayload.class);
			for (SensorIdentification sensorIdentification : sensors) {
				EcgSensorThread sensorThread = new EcgSensorThread(sensorConfig, sensorIdentification, writer);
				ISensorWindow sensorWindow = this.sensorWindow.get(sensorIdentification);
				sensorThread.setSensorWindow(sensorWindow);
				sensorThread.start();
				this.ecgs.add(sensorThread);
			}
		}
	}
	
	private void startAccs() {
		if(sensorConfig!=null){
			List<SensorIdentification> sensors = sensorConfig.getSensor(AccPayload.class);
			for (SensorIdentification sensorIdentification : sensors) {
				AccSensorThread sensorThread = new AccSensorThread(sensorConfig, sensorIdentification, writer);
				ISensorWindow sensorWindow = this.sensorWindow.get(sensorIdentification);
				sensorThread.setSensorWindow(sensorWindow);
				sensorThread.start();
				this.accs.add(sensorThread);
			}
		}
	}

	private void startTemperatures() {
		if(sensorConfig!=null){
			List<SensorIdentification> sensors = sensorConfig.getSensor(TemperaturePayload.class);
			for (SensorIdentification sensorIdentification : sensors) {
				TemperatureSensorThread sensorThread = new TemperatureSensorThread(sensorConfig, sensorIdentification, writer);
				ISensorWindow sensorWindow = this.sensorWindow.get(sensorIdentification);
				sensorThread.setSensorWindow(sensorWindow);
				sensorThread.start();
				this.temperatures.add(sensorThread);
			}
		}
	}

	private void startSPO2s() {
		if(sensorConfig!=null){
			List<SensorIdentification> sensors = sensorConfig.getSensor(Spo2Payload.class);
			for (SensorIdentification sensorIdentification : sensors) {
				SPO2SensorThread sensorThread = new SPO2SensorThread(sensorConfig, sensorIdentification, writer);
				ISensorWindow sensorWindow = this.sensorWindow.get(sensorIdentification);
				sensorThread.setSensorWindow(sensorWindow);
				sensorThread.start();
				this.spo2s.add(sensorThread);
			}
		}
		
	}

	private void stopSensing() {
		if(this.isSensing){
			this.stopSPO2s();
			this.stopTemperatures();
			this.stopEcgs();
			this.stopAccs();
			this.isSensing = false;
		}
	}

	private boolean isSearchCommand(CommandPayload comm) {
		if(comm.getCommand().equals(DataPackageConstant.comm_search_sensing_command)){
			return true;
		}
		return false;
	}

	private boolean isStartCommand(CommandPayload comm) {
		if(comm.getCommand().equals(DataPackageConstant.comm_start_sensing_command)){
			return true;
		}
		return false;
	}
	
	private boolean isStopCommand(CommandPayload comm) {
		if(comm.getCommand().equals(DataPackageConstant.comm_stop_sensing_command)){
			return true;
		}
		return false;
	}

	public void setSensorWindow(Map<SensorIdentification, ISensorWindow> sensorWindows) {
		this.sensorWindow = sensorWindows;
	}

	public void setWriter(BluetoothConnection bConnection) {
		this.writer = bConnection;
	}
}
